package httpsrv

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"gitee.com/JMArch/rpcmon-gateway/storage"
	"gitee.com/JMArch/rpcmon-gateway/util"
	jwt "github.com/dgrijalva/jwt-go"
	"go.uber.org/zap"
)

func (srv *HttpSrv) LogInfoHandler(w http.ResponseWriter, req *http.Request) {

	defer func() {
		if p := recover(); p != nil {
			srv.log.Error("loginfo panic", zap.Any("error", p))
		}
	}()

	select {
	case <-srv.quit:
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	default:
	}

	req.ParseForm()

	tokenStr := req.Form.Get("token")
	if tokenStr == "" {
		srv.log.Error("token miss", zap.String("remote", req.RemoteAddr))
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	token, err := jwt.ParseWithClaims(tokenStr, jwt.MapClaims{},
		func(token *jwt.Token) (interface{}, error) {
			return []byte(secretKey), nil
		})

	if err != nil || token.Valid == false {
		srv.log.Error("token invalid", zap.String("remote", req.RemoteAddr), zap.Error(err))
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	logType := req.Form.Get("logtype")
	if logType == "" {
		srv.log.Error("logType miss", zap.String("remote", req.RemoteAddr))
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	pID := req.Form.Get("pid")
	if pID == "" {
		srv.log.Error("pID miss", zap.String("remote", req.RemoteAddr))
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	logID := req.Form.Get("logid")
	if logID == "" {
		srv.log.Error("logID miss", zap.String("remote", req.RemoteAddr))
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	elasticIndex := req.Form.Get("elasticindex")
	if elasticIndex == "" {
		srv.log.Error("elasticIndex miss", zap.String("remote", req.RemoteAddr))
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	addrConf, ok := srv.conf.OWL.BackendMap[logType]
	if !ok {
		srv.log.Error("logType invalid", zap.String("remote", req.RemoteAddr))
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	query := fmt.Sprintf("http://%s/%s/log/%s?pId=%s&elasticIndex=%s", addrConf.Addr, logType, logID, pID, elasticIndex)

	srv.log.Debug("detail log", zap.String("url", query))

	client := &http.Client{}
	request, err := http.NewRequest("GET", query, nil)
	if err != nil {
		srv.log.Error("http new request fail", zap.Error(err))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	request.Header.Add("Authorization", util.GetAuth())

	resp, err := client.Do(request)
	if err != nil {
		srv.log.Error("http get fail", zap.String("url", query), zap.Error(err))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		srv.log.Error("http get fail", zap.String("url", query), zap.Error(err))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	hmap := make(map[string]interface{}, 0)
	err = json.Unmarshal(body, &hmap)
	if err != nil {
		srv.log.Error("http get fail", zap.String("url", query), zap.String("body", string(body)), zap.Error(err))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	if _, ok := hmap["data"]; !ok {
		srv.log.Error("detail log fail", zap.Any("result", string(body)))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	output := hmap["data"].(map[string]interface{})
	cnt, err := json.Marshal(output)
	if err != nil {
		srv.log.Error("json marshal fail", zap.String("remote", req.RemoteAddr), zap.Error(err))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	w.Header().Set("Access-Control-Allow-Origin", "wx-mon.int.jumei.com")
	w.WriteHeader(http.StatusOK)
	w.Write(cnt)
	return
}

func (srv *HttpSrv) OWLServiceListHandler(w http.ResponseWriter, req *http.Request) {

	defer func() {
		if p := recover(); p != nil {
			srv.log.Error("loginfo panic", zap.Any("error", p))
		}
	}()

	select {
	case <-srv.quit:
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	default:
	}

	m, err := util.GetOWLServicesList(srv.conf.OWL.Menus)
	if err != nil {
		srv.log.Error("get service list fail", zap.String("remote", req.RemoteAddr), zap.Error(err))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	output := make([]map[string]string, 0)
	for k, v := range m {
		item := map[string]string{
			"ID":   strconv.Itoa(k),
			"Name": v,
		}
		output = append(output, item)
	}

	cnt, err := json.Marshal(output)
	if err != nil {
		srv.log.Error("json marshal fail", zap.String("remote", req.RemoteAddr), zap.Error(err))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	w.Header().Set("Access-Control-Allow-Origin", "wx-mon.int.jumei.com")
	w.WriteHeader(http.StatusOK)
	w.Write(cnt)
	return
}

func (srv *HttpSrv) QueryLogHandler(w http.ResponseWriter, req *http.Request) {

	defer func() {
		if p := recover(); p != nil {
			srv.log.Error("loginfo panic", zap.Any("error", p))
		}
	}()

	select {
	case <-srv.quit:
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	default:
	}

	req.ParseForm()

	tokenStr := req.Form.Get("token")
	if tokenStr == "" {
		srv.log.Error("token miss", zap.String("remote", req.RemoteAddr))
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	token, err := jwt.ParseWithClaims(tokenStr, jwt.MapClaims{},
		func(token *jwt.Token) (interface{}, error) {
			return []byte(secretKey), nil
		})

	if err != nil || token.Valid == false {
		srv.log.Error("token invalid", zap.String("remote", req.RemoteAddr), zap.Error(err))
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	logType := req.Form.Get("type")
	if logType == "" {
		srv.log.Error("type is nil", zap.String("remote", req.RemoteAddr))
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	service := req.Form.Get("service")
	if service == "" {
		srv.log.Error("service is nil", zap.String("remote", req.RemoteAddr))
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	cfg, ok := srv.conf.OWL.BackendMap[logType]
	if !ok {
		srv.log.Error("service is invalid", zap.String("remote", req.RemoteAddr))
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	key := req.Form.Get("key")
	pageIndex := req.Form.Get("pageindex")
	pageSize := req.Form.Get("pagesize")
	mode := req.Form.Get("mode")

	end := time.Now()
	m, _ := time.ParseDuration("-1h")
	begin := end.Add(m)

	query := fmt.Sprintf("http://%s%s?pId=%s&beginTime=%s&endTime=%s", cfg.Addr, cfg.Path, service, url.PathEscape(begin.Format("2006-01-02 15:04:05")), url.PathEscape(end.Format("2006-01-02 15:04:05")))
	if key != "" {
		query += fmt.Sprintf("&keyword=%s", key)
	}
	if pageIndex != "" && pageSize != "" {
		query += fmt.Sprintf("&page=%s&pageSize=%s", pageIndex, pageSize)
	}
	if mode != "" {
		query += fmt.Sprintf("&preOperator=%s", mode)
	}

	srv.log.Debug("query log", zap.String("url", query))

	client := &http.Client{}
	request, err := http.NewRequest("GET", query, nil)
	if err != nil {
		srv.log.Error("http new request fail", zap.Error(err))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	request.Header.Add("Authorization", util.GetAuth())

	resp, err := client.Do(request)
	if err != nil {
		srv.log.Error("http get fail", zap.String("url", query), zap.String("authKey", request.Header.Get("Authorization")), zap.Error(err))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		srv.log.Error("http get fail", zap.String("url", query), zap.String("authKey", request.Header.Get("Authorization")), zap.Int("code", resp.StatusCode))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		srv.log.Error("http read fail", zap.String("url", query), zap.String("authKey", request.Header.Get("Authorization")), zap.Error(err))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	hmap := make(map[string]interface{}, 0)
	err = json.Unmarshal(body, &hmap)
	if err != nil {
		srv.log.Error("http decode fail", zap.String("url", query), zap.String("authKey", request.Header.Get("Authorization")), zap.String("body", string(body)), zap.Error(err))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	var output struct {
		Content       []storage.Node `json:"Content"`
		PageTotalSize string         `json:"PageTotalSize"`
	}

	bucket := make([]storage.Node, 0)
	if _, ok := hmap["data"]; ok {

		detail := hmap["data"].(map[string]interface{})
		size := int(detail["page_total_num"].(float64))
		arr := detail["page_data"].([]interface{})
		for i, _ := range arr {
			item := arr[i].(map[string]interface{})
			t := item["time"].(string)
			host := item["host"].(string)
			id := item["log_id"].(string)
			title := item["title"].(string)
			esc := item["elasticIndex"].(string)

			node := make(storage.Node, 0)
			node["Service"] = service
			node["LogID"] = id
			node["Host"] = host
			node["Title"] = title
			node["Create"] = t
			node["ElasticIndex"] = esc

			bucket = append(bucket, node)

		}

		output.Content = bucket
		output.PageTotalSize = strconv.Itoa(size)
	} else {
		srv.log.Error("query log fail", zap.Any("result", string(body)))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	cnt, err := json.Marshal(output)
	if err != nil {
		srv.log.Error("json marshal fail", zap.String("remote", req.RemoteAddr), zap.Error(err))
		w.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	w.Header().Set("Access-Control-Allow-Origin", "wx-mon.int.jumei.com")
	w.WriteHeader(http.StatusOK)
	w.Write(cnt)

	return

}
